/* INCLUDES ******************************************************************/
#include "ses_adc.h"
#include "ses_common.h"
#include "ses_led.h"
#include <avr/interrupt.h>

/* DEFINES & MACROS **********************************************************/

#define ADC_TEMP_TABLE_SIZE  (sizeof(adcTempTable) / sizeof(uint16_t))
#define ADC_TEMP_MIN           0    /* minimum temp [dC]      */
#define ADC_TEMP_STEP         50    /* stepping in table [dC] */
#define ADC_TEMP_MAX          500   /* maximum temp[dC]*/
/* PRIVATE VARIABLES *********************************************************/

static const uint16_t adcTempTable[] = { 888, 762, 655, 560, 479, 410, 351, 301,
		259, 223, 192 };
volatile bool flag = false;

/* FUNCTION DEFINITION *******************************************************/

void adc_init(void) {
	DDR(ADC_MIC_NEG_PORT) &= ~(1 << ADC_MIC_NEG_PIN);
	DDR(ADC_MIC_POS_PORT) &= ~(1 << ADC_MIC_POS_PIN);
	DDR(ADC_TEMP_PORT) &= ~(1 << ADC_TEMP_PIN);
	DDR(ADC_LIGHT_PORT) &= ~(1 << ADC_LIGHT_PIN);
	DDR(ADC_JOYSTICK_PORT) &= ~(1 << ADC_JOYSTICK_PIN);
	ADC_MIC_NEG_PORT &= ~(1 << ADC_MIC_NEG_PIN);
	ADC_MIC_POS_PORT &= ~(1 << ADC_MIC_POS_PIN);
	ADC_TEMP_PORT &= ~(1 << ADC_TEMP_PIN);
	ADC_LIGHT_PORT &= ~(1 << ADC_LIGHT_PIN);
	ADC_JOYSTICK_PORT &= ~(1 << ADC_JOYSTICK_PIN);
	PRR0 &= ~(1 << PRADC);     //disable power induction mode;
	ADCSRB &= ~(1 << MUX5);
    ADMUX &= ~(1 << MUX0) | ~(1 << MUX1) | ~(1 << MUX2) | ~(1 << MUX3)
			| ~(1 << MUX4);    //initialize the ADC channel.
	ADMUX = (ADC_VREF_SRC << REFS0);	// Reference mode selection.
    ADMUX &= ~(1 << ADLAR);	  // ADC Left Adjust Result
	ADCSRA = (1 << ADEN) |	// ADC Enable
			(1 << ADIE) |		// ADC Interrupt Enable
			(ADC_PRESCALE << ADPS0);	// ADC Prescaler 64 Select
	ADCSRA &= ~(0 << ADATE);     // ADC Auto Trigger Enable(0<<ADIF)


}

uint16_t adc_read(uint8_t adc_channel) {

	uint16_t result;
	if ((adc_channel == 3) | (adc_channel == 6) | (adc_channel == 7)
			| (adc_channel >= ADC_NUM)) {
		result = ERROR;
	} else {
		ADMUX |= (adc_channel << MUX0);
		ADCSRA |= (1 << ADSC);
		while (!flag) {
			//TIMSK2 &= ~(1 << OCIE2A); //disable scheduler interruption to avoid waking up node.
			sleep_cpu()
			;
		}
		//TIMSK2 |= (1 << OCIE2A);
		result = ADC;
		flag = false;
	}
	return result;
}

void adc_disable(void) {
	ADCSRA &= ~(1 << ADEN);    //disable ADC.
	PRR0 |= (1 << PRADC);    //enable power reduction mode.
}

/* NOTE This only works in case of monotonically descending values in adcTempTable */
int16_t adc_convertTemp(uint16_t val) {
	uint16_t temp = 0;
	int16_t result = 0;
	if (val < adcTempTable[10]) {
		result = ADC_TEMP_MAX;
	} else if (val > adcTempTable[0]) {
		result = ADC_TEMP_MIN;
	} else {
		for (uint8_t i = 0; i < 10; i++) {

			if (val <= adcTempTable[i] && val >= adcTempTable[i + 1]) {
				result = temp
						+ (((adcTempTable[i] - val) * ADC_TEMP_STEP)
								/ (adcTempTable[i] - adcTempTable[i + 1]));
				break;
			}
			temp += ADC_TEMP_STEP;
		}
	}
	return result;
}

ISR(ADC_vect) {

	flag = true;

}
